from django.shortcuts import render
from utils.views import LoginRequiredJSONMixin
from django.views import View
import time
from apps.areas.models import Address
from django_redis import get_redis_connection
from apps.goods.models import SKU
import decimal
from django.http import JsonResponse
import json
from apps.areas.models import Address
from django.utils import timezone
from apps.orders.models import OrderInfo,OrderGoods
from apps.goods.models import SKU
from django.db import transaction

class OrderSettlementView(LoginRequiredJSONMixin, View):
    """结算订单"""

    def get(self,request):
        # 1.获得该登录用户的收货地址列表，
        AddressList=Address.objects.filter(user_id=request.user.id,is_deleted=False)
        # 2.获得该用户的redis商品购物车数据，
        cli=get_redis_connection('carts')
        redis_carts=cli.hgetall(request.user.id)
        # 筛选出购物车中选中的商品，
        selected = []  # 记录用户选择了那些视频
        for k in redis_carts.keys():
            if int(redis_carts[k])>0:
                selected.append(int(k))
        # 通过商品数据找到指定商品的详细信息，
        skus=SKU.objects.filter(id__in=selected)
        # 补充运费
        freight = decimal.Decimal('10.00')
        # 格式化数据
        addresses_list = [] #地址数据
        for address in AddressList:
            addresses_list.append({
                'id': address.id,
                'province': address.province.name,
                'city': address.city.name,
                'district': address.district.name,
                'place': address.place,
                'receiver': address.receiver,
                'mobile': address.mobile
            })
        sku_list=[] #购物车已选中商品信息
        for sku in skus:
            sku_list.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'count': redis_carts[str(sku.id).encode()].decode(),
                'price': sku.price
            })

        # 数据整合
        context = {
            'addresses': addresses_list,
            'skus': sku_list,
            'freight': freight,
        }
        # 3.返回json
        return JsonResponse({'code':0,'errmsg':'ok','context':context})


class OrderCommitView(LoginRequiredJSONMixin, View):
    """订单提交"""

    def post(self,request):
        # 1.拿到前端数据
        datas=json.loads(request.body.decode())
        address_id=datas.get('address_id') #收货地址id
        pay_method=datas.get('pay_method') #支付方式
        # 2.数据校验
        if not all([address_id,pay_method]):
            return JsonResponse({'code':400,'errmsg':'数据缺失，请查看是否选择了收货地址和支付方式'})

        try:
            address=Address.objects.get(id=address_id) #获得收货地址
        except Exception:
            return JsonResponse({'code':400,'errmsg':'地址有误'})

        if not pay_method in OrderInfo.PAY_METHODS_ENUM.values():
            return JsonResponse({'code': 400, 'errmsg': '支付方式有误'})
        # 3.保存订单基础信息
        # 创建订单号

        order_id=timezone.datetime.now().strftime('%Y%m%d%H%M%S%f') + ('%09d' % request.user.id)
        #商品总数,商品总金额先为0，保存视商品详细信息的时候统一更改
        total_count=0 #商品总数
        total_amount=decimal.Decimal('0.00') #商品总金额
        freight=OrderInfo.FREIGHT #运费
        with transaction.atomic(): #开始事务
            # 创建保存点
            save_id = transaction.savepoint()
            #保存订单基础数据
            orderInfo=OrderInfo.objects.create(
                order_id=order_id,
                user=request.user,
                address=address,
                total_count=total_count,
                total_amount=total_amount,
                freight=freight,
                pay_method=pay_method,
                status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY'] else OrderInfo.ORDER_STATUS_ENUM['UNSEND']
            )
            # 4.保存订单商品详细信息
            #查询用户redis购物车，找到已选中的商品，入库保存商品详细信息
            cli=get_redis_connection('carts')
            carts=cli.hgetall(request.user.id)
            cli_pip = cli.pipeline()
            is_selecte=False
            for k,v in carts.items():
                if int(v) > 0: #判断商品是否选中，选中保存数据库
                    is_selecte=True
                    while True:
                        try:
                            sku=SKU.objects.get(id=int(k))
                        except Exception:
                            # 事务回滚到保存点
                            transaction.savepoint_rollback(save_id)
                            return JsonResponse({'code':400,'errmsg':'商品信息错误'})
                        # 读取原始库存
                        origin_stock = sku.stock
                        origin_sales = sku.sales
                        if origin_stock < int(v) : #用户的订单商品数量大于商品库存
                            # 事务回滚到保存点
                            transaction.savepoint_rollback(save_id)
                            return JsonResponse({'code':400,'errmsg':'{}\t该商品库存不足'.format(sku.name)})
                        #有库存则sku库存-count，sku销量（sales）+count
                        # sku.stock-=int(v)
                        # sku.sales+=int(v)
                        # 乐观锁更新库存和销量
                        new_stock = origin_stock - int(v)
                        new_sales = origin_sales + int(v)
                        result = SKU.objects.filter(id=sku.id, stock=origin_stock,sales=origin_sales).update(stock=new_stock,sales=new_sales)
                        # 如果下单失败，但是库存足够时，继续下单，直到下单成功或者库存不足为止
                        if result == 0:
                            time.sleep(0.05)
                            continue
                        #保存订单商品信息
                        OrderGoods.objects.create(
                            order_id=order_id,
                            sku=sku,
                            count=int(v),
                            price=sku.price,
                        )
                        total_count+=int(v) #设置商品总数
                        total_amount+=sku.price*int(v)
                        ## 清除redis购物车中已结算的商品
                        cli_pip.hdel(request.user.id,int(k))
                        break
            if not is_selecte:
                # 事务回滚到保存点
                transaction.savepoint_rollback(save_id)
                return JsonResponse({'code': 400, 'errmsg': '购物车没有商品'})
            cli_pip.execute()
            #更新订单基础信息的商品总数, 商品总金额
            orderInfo.total_count=total_count
            orderInfo.total_amount=total_amount+freight
            orderInfo.save()
            # 提交从保存点到当前状态的所有数据库事务操作
            transaction.savepoint_commit(save_id)
        # 5.返回数据
        return JsonResponse({'code':0,'errmsg':'ok','order_id':order_id})


class OrderListView(View):
    """展示用户全部订单"""
    def get(self,request):
        # 1.判断用户是否登录
        if not request.user.is_authenticated:
            # 2.未登录直接返回
            return JsonResponse({'code':'ok','errmsg':'用户未登录','order_list':[]})
        # 3.登录了，查询用户的订单数据
        orders=OrderInfo.objects.filter(user_id=request.user.id).order_by('-create_time')
        user_skus=[] #保存商品数据  #格式[{订单时间:,订单号:,商品:[]},{}]
        for order in orders:
            skus=OrderGoods.objects.filter(order_id=order.order_id)
            skus_data=[] #商品信息
            for sku in skus:
                try:
                    goods_sku=SKU.objects.get(id=sku.sku_id)
                except Exception:
                    return JsonResponse({'code':400,'errmsg':'商品错误','order_list':[]})
                # 4.格式化数据
                skus_name=goods_sku.name
                if len(goods_sku.name)>=30:
                    skus_name=str(goods_sku.name)[:30]+'...'
                skus_data.append({
                    'name':skus_name, #商品名
                    'sku_id':goods_sku.id, #商品id
                    'count':sku.count, #商品数量
                    'price':str(goods_sku.price), #商品单价
                    'sku_img':goods_sku.default_image.url #商品
                })

            user_skus.append({
                'create_time':'{:%Y-%m-%d %H:%M:%S}'.format(order.create_time),#订单时间
                'order_id':order.order_id,#订单号
                'total_amount':str(order.total_amount), #总价
                'pay_method':OrderInfo.MY_PAY_METHODS_ENUM[str(order.pay_method)], #支付方式
                'status':OrderInfo.MY_ORDER_STATUS_ENUM[str(order.status)],#订单状态
                'skus':skus_data #商品信息
                })
        # 5.返回数据
        return JsonResponse({'code':0,'errmsg':'ok','order_list':user_skus})

from alipay import AliPayConfig,AliPay
from meiduo import settings
class OrderSysView(LoginRequiredJSONMixin,View):
    """管理用户订单状态"""
    def get(self,request):
        #1.接受前端参数
        status=request.GET.get('status')
        order_id=request.GET.get('order_id')
        #2.校验参数
        if not str(status) in OrderInfo.MY_ORDER_STATUS_ENUM.keys():
            return JsonResponse({'code':400,'errmsg':'非法参数'})
        #查询数据库信息
        try:
            order= OrderInfo.objects.get(order_id=order_id)
        except Exception:
            return JsonResponse({'code':400,'errmsg':'非法数据，哥你别乱玩'})
        #3.判断用户的订单状态，
        if int(status) == OrderInfo.ORDER_STATUS_ENUM['UNPAID']:
            # 3.1订单状态为待支付，
            # 3.1.1获得支付宝请求
            # 创建实例
            app_private_key_string = open(settings.APP_PRIVATE_KEY_PATH).read()
            alipay_public_key_string = open(settings.ALIPAY_PUBLIC_KEY_PATH).read()
            alipay = AliPay(
                appid="2021000122675584",
                app_notify_url=None,  # 默认回调 url
                app_private_key_string=app_private_key_string,
                # 支付宝的公钥，验证支付宝回传消息使用，不是你自己的公钥,
                alipay_public_key_string=alipay_public_key_string,
                sign_type="RSA2",  # RSA 或者 RSA2
                debug=False,  # 默认 False
                verbose=False,  # 输出调试数据
                config=AliPayConfig(timeout=15)  # 可选，请求超时时间
            )
            # 获得支付宝url
            subject = "阿威小店--订单号：{}".format(order.order_id)  # 标题

            # 电脑网站支付，需要跳转到：https://openapi.alipay.com/gateway.do? + order_string
            order_string = alipay.api_alipay_trade_page_pay(
                out_trade_no=order.order_id,
                total_amount=str(order.total_amount),
                subject=subject,
                return_url=settings.ALIPAY_RETURN_URL,
                notify_url="https://example.com/notify"  # 可选，不填则使用默认 notify url
            )
            alipay_url = settings.ALIPAY_URL + "?" + order_string
            return JsonResponse({'code': 0, 'errmsg': 'ok', 'alipay_url': alipay_url})


from apps.goods.models import GoodsComment
from utils.goods import count_elements
class CommentOrNot(View):
    """是否评论"""
    def get(self,request):
        order_id=request.GET.get('orderId')
        skus=GoodsComment.objects.filter(order_id=order_id)
        if len(skus) <=0:
            return JsonResponse({'code': 202, 'errmsg': 'ok'})
        sku_id_list =[]
        for item in skus:
            sku_id_list.append(item.sku_id)
        #统计sku评论数量
        sku_id_list=count_elements(sku_id_list)
        return JsonResponse({'code': 201, 'errmsg': 'ok','skuIdList':sku_id_list})

from utils.customEncryption import  jiami
class delOrder(View):
    """删除订单"""
    def get(self,request):
        #拿到前端参数
        try:
            user=jiami(expires_in=60*60*12*14).decrypt(request.GET.get('key'))
        except Exception:
            return JsonResponse({'code': 204, 'errmsg': '参数错误'})

        order_id=request.GET.get('orderId')
        #数据库删除
        try:
            OrderInfo.objects.get(order_id=order_id,user_id=user).delete()
        except Exception:
            return JsonResponse({'code': 204, 'errmsg': '参数错误'})

        return JsonResponse({'code': 202, 'errmsg': '删除成功'})

from apps.orders.models import OrderInfo
class noOrders(View):
    """取消订单"""
    # 拿到前端参数
    def get(self,request):
        try:
            user = jiami(expires_in=60 * 60 * 12 * 14).decrypt(request.GET.get('key'))
        except Exception:
            return JsonResponse({'code': 204, 'errmsg': '参数错误'})

        order_id = request.GET.get('orderId')
        # 数据库删除
        try:
            OrderInfo.objects.filter(order_id=order_id, user_id=user).update(status=OrderInfo.ORDER_STATUS_ENUM['CANCEL'])
        except Exception:
            return JsonResponse({'code': 204, 'errmsg': '参数错误'})

        return JsonResponse({'code': 202, 'errmsg': '订单取消成功'})



